package projeto.lp2.grupo6.testes;

import java.util.ArrayList;
import java.util.List;
import org.junit.*;
import projeto.lp2.grupo6.logica.Estabelecimento;
import projeto.lp2.grupo6.logica.RecomendacaoPorPopularidade;
import projeto.lp2.grupo6.logica.TipoDeAlmocoServido;
import projeto.lp2.grupo6.logica.Usuario;

/*
 *     e1  e2  e3
 * u1  2  -2   4
 * u2  0   0   0
 * u3  0  -3   5
 * u4  0  -3   5
 * 
 */

/**
 * Aluno: 
 *      Guilherme Monteiro
 *      Italo Guedes
 *      Tiago Leite
 * 
 * @author guilhermemg
 * @author tiagoln
 * @author italogas
 *
 */
public class RecomendacaoPorPopularidadeTest {
    RecomendacaoPorPopularidade recPorPop;

    List<Usuario> listaUsuarios;

    Usuario u1;
    Usuario u2;
    Usuario u3;
    Usuario u4;

    Estabelecimento e1;
    Estabelecimento e2;
    Estabelecimento e3;

    List<TipoDeAlmocoServido> listaTipos1 = new ArrayList<TipoDeAlmocoServido>();
    List<TipoDeAlmocoServido> listaTipos2 = new ArrayList<TipoDeAlmocoServido>();
    List<TipoDeAlmocoServido> listaTipos3 = new ArrayList<TipoDeAlmocoServido>();

    @Before
    public void setup() {
        try {
            listaUsuarios = new ArrayList<Usuario>();
            u1 = new Usuario("nome1");
            u2 = new Usuario("Nome2");
            u3 = new Usuario("Nome3");
            u4 = new Usuario("Nome4");

            e1 = new Estabelecimento("nomeEstab1", "rua1", TipoDeAlmocoServido.A_LA_CARTE);
            e2 = new Estabelecimento("nomeEstab2", "rua2", TipoDeAlmocoServido.SELF_SERVICE);
            e3 = new Estabelecimento("nomeEstab3", "rua3", TipoDeAlmocoServido.PRATO_FEITO);

            u1.adicionaOpiniao(e1, 2);
            u1.adicionaOpiniao(e2, -2);
            u1.adicionaOpiniao(e3, 4);

            u2.adicionaOpiniao(e1, 0);
            u2.adicionaOpiniao(e2, 0);
            u2.adicionaOpiniao(e3, 0);

            u3.adicionaOpiniao(e1, 0);
            u3.adicionaOpiniao(e2, -3);
            u3.adicionaOpiniao(e3, 5);

            u4.adicionaOpiniao(e1, 0);
            u4.adicionaOpiniao(e2, -3);
            u4.adicionaOpiniao(e3, 5);

            listaTipos1.add(TipoDeAlmocoServido.A_LA_CARTE);
            listaTipos1.add(TipoDeAlmocoServido.SELF_SERVICE);

            listaTipos2.add(TipoDeAlmocoServido.PRATO_FEITO);

            listaTipos3.add(TipoDeAlmocoServido.A_LA_CARTE);
            listaTipos3.add(TipoDeAlmocoServido.PRATO_FEITO);
            listaTipos3.add(TipoDeAlmocoServido.SELF_SERVICE);

            listaUsuarios.add(u1);
            listaUsuarios.add(u2);
            listaUsuarios.add(u3);
            listaUsuarios.add(u4);

            recPorPop = new RecomendacaoPorPopularidade(listaUsuarios);

        }
        catch(Exception e) {
            Assert.fail("Nao esperava erro em construir objetos: " + e.getMessage());
        }
    }

    @Test
    public void testaConstrutor() {
        try {
            recPorPop = new RecomendacaoPorPopularidade(null);
        }
        catch(Exception e) {
            Assert.assertEquals("Erro em lista de usuarios nula", e.getMessage());
        }
        try {
            recPorPop = new RecomendacaoPorPopularidade(new ArrayList<Usuario>());
        }
        catch(Exception e) {
            Assert.assertEquals("Erro em lista de usuarios vazia", e.getMessage());
        }
    }

    @Test
    public void testaGetRecomendacao() throws Exception {
        recPorPop = new RecomendacaoPorPopularidade(listaUsuarios);

        try {
            recPorPop.getRecomendacao(0, listaTipos1, "bar");
        }
        catch(Exception e) {
            Assert.assertEquals("Erro em quantidade de itens nula", e.getMessage());
        }
        try {
            recPorPop.getRecomendacao(-3, listaTipos1, "bar");
        }
        catch(Exception e) {
            Assert.assertEquals("Erro em quantidade de itens negativa", e.getMessage());
        }
        try {
            recPorPop.getRecomendacao(2, null, "bar");
        }
        catch(Exception e) {
            Assert.assertEquals("Erro em lista de tipos de almoco servidos nula", e.getMessage());
        }
        try {
            ArrayList<TipoDeAlmocoServido> listaTiposVazia = new ArrayList<TipoDeAlmocoServido>();
            recPorPop.getRecomendacao(2, listaTiposVazia, null);
        }
        catch(Exception e) {
            Assert.assertEquals("Erro em lista de tipos de almoco servidos vazia", e.getMessage());
        }
        try {
            recPorPop.getRecomendacao(2, listaTipos1, null);
        }
        catch(Exception e) {
            Assert.assertEquals("Erro em palavra-chave nula", e.getMessage());
        }
        try {
            recPorPop.getRecomendacao(2, listaTipos1, "");
        }
        catch(Exception e) {
            Assert.assertEquals("Erro em palavra-chave vazia", e.getMessage());
        }

        try {
            ArrayList<Estabelecimento> listaResultados = new ArrayList<Estabelecimento>();
            listaResultados.add(e3);
            listaResultados.add(e1);
            listaResultados.add(e2);
            Assert.assertEquals(listaResultados, recPorPop.getRecomendacao(3, listaTipos3, "---"));
        }
        catch(Exception e) {
            Assert.fail("Nao esperava erro em lista de resultados de getRecomendacao test-2");
        }

        try {
            ArrayList<Estabelecimento> listaResultados = new ArrayList<Estabelecimento>();
            listaResultados.add(e3);
            listaResultados.add(e1);
            Assert.assertEquals(listaResultados, recPorPop.getRecomendacao(2, listaTipos3, "---"));
        }
        catch(Exception e) {
            Assert.fail("Nao esperava erro em lista de resultados de getRecomendacao test-1");
        }

        try {
            ArrayList<Estabelecimento> listaResultados = new ArrayList<Estabelecimento>();
            listaResultados.add(e1);
            listaResultados.add(e2);
            Assert.assertEquals(listaResultados, recPorPop.getRecomendacao(3, listaTipos1, "---"));
        }
        catch(Exception e) {
            Assert.fail("Nao esperava erro em lista de resultados de getRecomendacao test0");
        }
        try {
            ArrayList<Estabelecimento> listaResultados = new ArrayList<Estabelecimento>();
            listaResultados.add(e1);
            listaResultados.add(e2);
            Assert.assertEquals(listaResultados, recPorPop.getRecomendacao(2, listaTipos1, "---"));
        }
        catch(Exception e) {
            Assert.fail("Nao esperava erro em lista de resultados de getRecomendacao test1");
        }
        try {
            ArrayList<Estabelecimento> listaResultados = new ArrayList<Estabelecimento>();
            listaResultados.add(e1);
            Assert.assertEquals(listaResultados, recPorPop.getRecomendacao(1, listaTipos1, "---"));
        }
        catch(Exception e) {
            Assert.fail("Nao esperava erro em lista de resultados de getRecomendacao test2");
        }
        try {
            ArrayList<Estabelecimento> listaResultados = new ArrayList<Estabelecimento>();
            listaResultados.add(e1);
            Assert.assertEquals(listaResultados, recPorPop.getRecomendacao(1, listaTipos1, "---"));
        }
        catch(Exception e) {
            Assert.fail("Nao esperava erro em lista de resultados de getRecomendacao test3");
        }
        try {
            ArrayList<Estabelecimento> listaResultados = new ArrayList<Estabelecimento>();
            listaResultados.add(e3);
            Assert.assertEquals(listaResultados, recPorPop.getRecomendacao(3, listaTipos2, "---"));
        }
        catch(Exception e) {
            Assert.fail("Nao esperava erro em lista de resultados de getRecomendacao test4");
        }
        try {
            ArrayList<Estabelecimento> listaResultados = new ArrayList<Estabelecimento>();
            listaResultados.add(e3);
            Assert.assertEquals(listaResultados, recPorPop.getRecomendacao(2, listaTipos2, "---"));
        }
        catch(Exception e) {
            Assert.fail("Nao esperava erro em lista de resultados de getRecomendacao test5");
        }
        try {
            ArrayList<Estabelecimento> listaResultados = new ArrayList<Estabelecimento>();
            listaResultados.add(e3);
            Assert.assertEquals(listaResultados, recPorPop.getRecomendacao(1, listaTipos2, "---"));
        }
        catch(Exception e) {
            Assert.fail("Nao esperava erro em lista de resultados de getRecomendacao test6");
        }
        try {
            ArrayList<Estabelecimento> listaResultados = new ArrayList<Estabelecimento>();
            listaResultados.add(e3);
            listaResultados.add(e1);
            listaResultados.add(e2);
            Assert.assertEquals(listaResultados, recPorPop.getRecomendacao(3, listaTipos3, "---"));
        }
        catch(Exception e) {
            Assert.fail("Nao esperava erro em lista de resultados de getRecomendacao test7");
        }
        try {
            ArrayList<Estabelecimento> listaResultados = new ArrayList<Estabelecimento>();
            listaResultados.add(e3);
            listaResultados.add(e1);
            Assert.assertEquals(listaResultados, recPorPop.getRecomendacao(2, listaTipos3, "---"));
        }
        catch(Exception e) {
            Assert.fail("Nao esperava erro em lista de resultados de getRecomendacao test8");
        }
        try {
            ArrayList<Estabelecimento> listaResultados = new ArrayList<Estabelecimento>();
            listaResultados.add(e3);
            Assert.assertEquals(listaResultados, recPorPop.getRecomendacao(1, listaTipos3, "---"));
        }
        catch(Exception e) {
            Assert.fail("Nao esperava erro em lista de resultados de getRecomendacao test9");
        }
    }
}
